﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Threading;
using System.Windows.Input;
using System.Windows.Data;

namespace Kokomo.Controls
{
	public class EnhancedTreeViewItem : TreeViewItem
	{
		public static readonly string EditorPartName = "PART_Editor";

		public static ICommand EndEditCommand { get; private set; }
		public static ICommand CancelEditCommand { get; private set; }

		static EnhancedTreeViewItem()
		{
			EndEditCommand = new RoutedCommand();
			CancelEditCommand = new RoutedCommand();
		}

		public EnhancedTreeViewItem()
		{
			this.CancelPendingEditEvent = new ManualResetEvent(false);

			this.CommandBindings.Add(new CommandBinding(EndEditCommand, EndEditCommand_Executed));
			this.CommandBindings.Add(new CommandBinding(CancelEditCommand, CancelEditCommand_Executed));
		}

		protected override DependencyObject GetContainerForItemOverride()
		{
			EnhancedTreeViewItem container = new EnhancedTreeViewItem();
			BindingBase textBinding = BindingOperations.GetBindingBase(this, TextProperty);
			if (textBinding != null)
			{
				container.SetBinding(EnhancedTreeViewItem.TextProperty, textBinding);
			}

			return container;
		}

		void EndEditCommand_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			this.IsEditing = false;
		}

		void CancelEditCommand_Executed(object sender, ExecutedRoutedEventArgs e)
		{
		}


		public DataTemplate EditTemplate
		{
			get { return (DataTemplate)GetValue(EditTemplateProperty); }
			set { SetValue(EditTemplateProperty, value); }
		}

		// Using a DependencyProperty as the backing store for EditTemplate.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty EditTemplateProperty =
			DependencyProperty.Register("EditTemplate", typeof(DataTemplate), typeof(EnhancedTreeViewItem), new UIPropertyMetadata(null));

		public string Text
		{
			get { return (string)GetValue(TextProperty); }
			set { SetValue(TextProperty, value); }
		}

		// Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty TextProperty =
			DependencyProperty.Register("Text", typeof(string), typeof(EnhancedTreeViewItem), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

		private IInputElement _editorPart;
		protected IInputElement EditorPart
		{
			get { return this._editorPart; }
			set
			{
				if (this._editorPart != null)
				{
					this._editorPart.LostKeyboardFocus -= new KeyboardFocusChangedEventHandler(EditorPart_LostKeyboardFocus);
				}
				this._editorPart = value;
				if (this._editorPart != null)
				{
					this._editorPart.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(EditorPart_LostKeyboardFocus);
				}
			}
		}

		void EditorPart_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
		{
			this.IsEditing = false;
		}
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();

			this.EditorPart = this.Template.FindName(EditorPartName, this) as IInputElement;
		}
		private void EnterEditMode()
		{
			this.IsEditing = true;
			if (this.EditorPart != null)
			{
				this.EditorPart.Focus();
			}
		}

		public bool IsEditing
		{
			get { return (bool)GetValue(IsEditingProperty); }
			set { SetValue(IsEditingProperty, value); }
		}

		// Using a DependencyProperty as the backing store for IsEditing.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty IsEditingProperty =
			DependencyProperty.Register("IsEditing", typeof(bool), typeof(EnhancedTreeViewItem), new UIPropertyMetadata(false));

		private ManualResetEvent CancelPendingEditEvent { get; set; }
		private void EditWaitProc()
		{
			TimeSpan doubleClickTime = TimeSpan.FromSeconds(0.5);
			bool r = this.CancelPendingEditEvent.WaitOne(doubleClickTime);

			this.Dispatcher.Invoke((Action)this.EnterEditMode);
		}

		public bool IsSelectedBeforeClick { get; private set; }



		public bool EditOnSelection
		{
			get { return (bool)GetValue(EditOnSelectionProperty); }
			set { SetValue(EditOnSelectionProperty, value); }
		}

		// Using a DependencyProperty as the backing store for EditOnSelection.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty EditOnSelectionProperty =
			DependencyProperty.Register("EditOnSelection", typeof(bool), typeof(EnhancedTreeViewItem), new UIPropertyMetadata(false));



		protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
		{
			this.IsSelectedBeforeClick = this.IsSelected;

			base.OnMouseLeftButtonDown(e);
		}
		protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e)
		{
			base.OnMouseLeftButtonUp(e);

			if (this.IsSelectedBeforeClick && this.IsSelected)
			{
				(new Thread(this.EditWaitProc)).Start();
			}
		}

		protected override void OnSelected(RoutedEventArgs e)
		{
			base.OnSelected(e);

			if (this.EditOnSelection)
			{
				this.EnterEditMode();
			}
		}

		public event EventHandler ItemActivated;
		protected virtual void OnItemActivated()
		{
			if (this.ItemActivated != null) this.ItemActivated(this, EventArgs.Empty);
		}

		protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
		{
			base.OnMouseDoubleClick(e);
			if (this.IsSelected) this.OnItemActivated();
		}
	}
}
